use std::collections::HashMap;

use crate::{
    PrivateKeyBytes, PublicKeyBytes, PublicKeyHashBytes, TransactionId,
    transaction::Transaction,
    wallet::{account::AccountManager, wallet_tx::WalletTx},
};

use crate::wallet::{ItemNumberInWalletDb, WalletBaseError};

#[derive(Debug, PartialEq)]
pub struct WalletCache {
    accounts: AccountManager,
    wallet_txs: HashMap<TransactionId, WalletTx>, // include utxos
}

impl Default for WalletCache {
    fn default() -> Self {
        Self::new()
    }
}

impl WalletCache {
    pub fn new() -> Self {
        Self {
            accounts: AccountManager::new(),
            wallet_txs: HashMap::new(),
        }
    }

    pub fn get_item_number(&self) -> ItemNumberInWalletDb {
        let t = self.accounts.get_item_number();

        ItemNumberInWalletDb {
            account_key_pair_number: t.account_key_pair_number,
            account_name_number: t.account_name_number,
            default_key_number: t.default_key_number,
            wallet_tx_number: self.wallet_txs.len(),
        }
    }
}

// for account
impl WalletCache {
    pub fn add_keypair(
        &mut self,
        public_key: &PublicKeyBytes,
        priv_key: &PrivateKeyBytes,
    ) -> Result<PublicKeyHashBytes, WalletBaseError> {
        let t = self.accounts.add_key_pair(public_key, priv_key)?;
        Ok(t)
    }

    pub fn add_account_name(
        &mut self,
        pub_key_hash: &PublicKeyHashBytes,
        name: &str,
    ) -> Result<(), WalletBaseError> {
        self.accounts.add_account_name(pub_key_hash, name)?;
        Ok(())
    }

    pub fn del_account(&mut self, public_key: &PublicKeyBytes) -> Result<(), WalletBaseError> {
        self.accounts.del_account(public_key)?;
        Ok(())
    }

    pub fn set_default_account_(
        &mut self,
        pub_key_hash: &PublicKeyHashBytes,
    ) -> Result<(), WalletBaseError> {
        self.accounts.set_default_account_(pub_key_hash)?;
        Ok(())
    }

    pub fn get_keypairs(&self) -> &HashMap<PublicKeyBytes, PrivateKeyBytes> {
        self.accounts.get_key_pairs()
    }

    pub fn get_account_names(&self) -> &HashMap<PublicKeyHashBytes, String> {
        self.accounts.get_account_names()
    }

    pub fn get_default_account(&self) -> &Option<PublicKeyHashBytes> {
        self.accounts.get_default_account()
    }

    pub fn get_pub_key(
        &self,
        pub_key_hash: &PublicKeyHashBytes,
    ) -> Result<PublicKeyBytes, WalletBaseError> {
        let t = self.accounts.get_pub_key(pub_key_hash)?;
        Ok(t)
    }

    pub fn get_private_key(
        &self,
        public_key: &PublicKeyBytes,
    ) -> Result<PrivateKeyBytes, WalletBaseError> {
        let t = self.accounts.get_private_key(public_key)?;
        Ok(t)
    }

    pub fn dump_accounts(&self) {
        self.accounts.dump()
    }

    pub fn is_mine(&self, pub_key_hash: &PublicKeyHashBytes) -> bool {
        self.accounts.is_mine(pub_key_hash)
    }

    pub fn is_mine_1(&self, public_key: &PublicKeyBytes) -> bool {
        self.accounts.is_mine_1(public_key)
    }
}

// for wallet tx
impl WalletCache {
    pub fn add_tx_to_wallet(&mut self, tx_id: &TransactionId, tx: &Transaction) {
        self.add_wallet_tx(tx_id, WalletTx::new(tx));
    }

    pub fn add_wallet_tx(&mut self, tx_id: &TransactionId, tx: WalletTx) {
        self.wallet_txs.insert(*tx_id, tx);
    }

    pub fn get_wallet_txs(&self) -> &HashMap<TransactionId, WalletTx> {
        &self.wallet_txs
    }

    pub fn get_wallet_tx(&self, tx_id: &TransactionId) -> Option<&WalletTx> {
        self.wallet_txs.get(tx_id)
    }

    pub fn is_tx_in_wallet(&self, tx_id: &TransactionId) -> bool {
        self.wallet_txs.contains_key(tx_id)
    }
}
